package com.iot.processor.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.iot.processor.model.SensorData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.time.format.DateTimeFormatter;

/**
 * Redis服务类
 * 负责与Redis的所有交互操作，包括连接管理和数据存储
 */
public class RedisService {
    
    private static final Logger logger = LoggerFactory.getLogger(RedisService.class);
    
    private final JedisPool jedisPool;
    private final ObjectMapper objectMapper;
    
    // Redis键的前缀
    private static final String SENSOR_DATA_KEY_PREFIX = "sensor:data:";
    private static final String DEVICE_STATS_KEY_PREFIX = "device:stats:";
    
    // 数据过期时间（24小时）
    private static final int DATA_EXPIRE_SECONDS = 24 * 60 * 60;
    
    /**
     * 构造函数，使用默认Redis配置
     */
    public RedisService() {
        this("localhost", 6379, null);
    }
    
    /**
     * 构造函数，指定Redis连接参数
     * 
     * @param host Redis主机地址
     * @param port Redis端口
     * @param password Redis密码（可为null）
     */
    public RedisService(String host, int port, String password) {
        // 配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(50);  // 最大连接数
        poolConfig.setMaxIdle(20);   // 最大空闲连接数
        poolConfig.setMinIdle(5);    // 最小空闲连接数
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(true);
        poolConfig.setTestWhileIdle(true);
        poolConfig.setMaxWaitMillis(Duration.ofSeconds(5).toMillis());
        
        // 创建连接池
        if (password != null && !password.trim().isEmpty()) {
            this.jedisPool = new JedisPool(poolConfig, host, port, 2000, password);
        } else {
            this.jedisPool = new JedisPool(poolConfig, host, port, 2000);
        }
        
        // 配置JSON序列化器
        this.objectMapper = new ObjectMapper();
        this.objectMapper.registerModule(new JavaTimeModule());
        
        logger.info("Redis连接池初始化完成，连接地址: {}:{}", host, port);
    }
    
    /**
     * 存储传感器数据到Redis
     * 使用Hash结构存储，Key格式：sensor:data:deviceId:timestamp
     * 
     * @param sensorData 传感器数据
     * @return 是否存储成功
     */
    public boolean storeSensorData(SensorData sensorData) {
        if (sensorData == null) {
            logger.warn("传感器数据为空，跳过存储");
            return false;
        }
        
        try (Jedis jedis = jedisPool.getResource()) {
            // 生成Redis键
            String key = generateSensorDataKey(sensorData);
            
            // 将对象转换为JSON字符串
            String jsonValue = objectMapper.writeValueAsString(sensorData);
            
            // 存储到Redis Hash结构
            jedis.hset(key, "data", jsonValue);
            jedis.hset(key, "deviceId", sensorData.getDeviceId());
            jedis.hset(key, "timestamp", sensorData.getTimestamp().toString());
            jedis.hset(key, "temperature", sensorData.getTemperature().toString());
            jedis.hset(key, "humidity", sensorData.getHumidity().toString());
            
            // 设置过期时间
            jedis.expire(key, DATA_EXPIRE_SECONDS);
            
            // 更新设备统计信息
            updateDeviceStats(jedis, sensorData);
            
            logger.debug("传感器数据存储成功: {}", key);
            return true;
            
        } catch (JsonProcessingException e) {
            logger.error("JSON序列化失败: {}", sensorData, e);
            return false;
        } catch (Exception e) {
            logger.error("存储传感器数据失败: {}", sensorData, e);
            return false;
        }
    }
    
    /**
     * 批量存储传感器数据
     * 
     * @param sensorDataArray 传感器数据数组
     * @return 成功存储的数量
     */
    public int batchStoreSensorData(SensorData[] sensorDataArray) {
        if (sensorDataArray == null || sensorDataArray.length == 0) {
            return 0;
        }
        
        int successCount = 0;
        try (Jedis jedis = jedisPool.getResource()) {
            // 开启管道模式提高批量操作性能
            var pipeline = jedis.pipelined();
            
            for (SensorData sensorData : sensorDataArray) {
                if (sensorData != null) {
                    try {
                        String key = generateSensorDataKey(sensorData);
                        String jsonValue = objectMapper.writeValueAsString(sensorData);
                        
                        pipeline.hset(key, "data", jsonValue);
                        pipeline.hset(key, "deviceId", sensorData.getDeviceId());
                        pipeline.hset(key, "timestamp", sensorData.getTimestamp().toString());
                        pipeline.hset(key, "temperature", sensorData.getTemperature().toString());
                        pipeline.hset(key, "humidity", sensorData.getHumidity().toString());
                        pipeline.expire(key, DATA_EXPIRE_SECONDS);
                        
                        successCount++;
                    } catch (JsonProcessingException e) {
                        logger.error("批量存储时JSON序列化失败: {}", sensorData, e);
                    }
                }
            }
            
            // 执行批量操作
            pipeline.sync();
            logger.info("批量存储完成，成功存储 {} 条数据", successCount);
            
        } catch (Exception e) {
            logger.error("批量存储传感器数据失败", e);
        }
        
        return successCount;
    }
    
    /**
     * 根据设备ID和时间戳获取传感器数据
     * 
     * @param deviceId 设备ID
     * @param timestamp 时间戳字符串
     * @return 传感器数据对象，如果不存在则返回null
     */
    public SensorData getSensorData(String deviceId, String timestamp) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = SENSOR_DATA_KEY_PREFIX + deviceId + ":" + timestamp.replace(":", "-");
            String jsonData = jedis.hget(key, "data");
            
            if (jsonData != null) {
                return objectMapper.readValue(jsonData, SensorData.class);
            }
            
        } catch (Exception e) {
            logger.error("获取传感器数据失败: deviceId={}, timestamp={}", deviceId, timestamp, e);
        }
        
        return null;
    }
    
    /**
     * 更新设备统计信息
     */
    private void updateDeviceStats(Jedis jedis, SensorData sensorData) {
        try {
            String statsKey = DEVICE_STATS_KEY_PREFIX + sensorData.getDeviceId();
            
            // 增加数据计数
            jedis.hincrBy(statsKey, "dataCount", 1);
            
            // 更新最后更新时间
            jedis.hset(statsKey, "lastUpdate", sensorData.getTimestamp().toString());
            
            // 更新最新的温湿度值
            jedis.hset(statsKey, "latestTemperature", sensorData.getTemperature().toString());
            jedis.hset(statsKey, "latestHumidity", sensorData.getHumidity().toString());
            
            // 设置统计信息过期时间（7天）
            jedis.expire(statsKey, 7 * 24 * 60 * 60);
            
        } catch (Exception e) {
            logger.warn("更新设备统计信息失败: deviceId={}", sensorData.getDeviceId(), e);
        }
    }
    
    /**
     * 生成传感器数据的Redis键
     */
    private String generateSensorDataKey(SensorData sensorData) {
        String timestampStr = sensorData.getTimestamp()
            .format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"));
        return SENSOR_DATA_KEY_PREFIX + sensorData.getDeviceId() + ":" + timestampStr;
    }
    
    /**
     * 测试Redis连接
     * 
     * @return 连接是否正常
     */
    public boolean testConnection() {
        try (Jedis jedis = jedisPool.getResource()) {
            String response = jedis.ping();
            boolean isConnected = "PONG".equals(response);
            logger.info("Redis连接测试: {}", isConnected ? "成功" : "失败");
            return isConnected;
        } catch (Exception e) {
            logger.error("Redis连接测试失败", e);
            return false;
        }
    }
    
    /**
     * 获取连接池状态信息
     */
    public String getPoolStatus() {
        return String.format("连接池状态 - 活跃连接: %d, 空闲连接: %d, 等待连接: %d",
            jedisPool.getNumActive(),
            jedisPool.getNumIdle(),
            jedisPool.getNumWaiters());
    }
    
    /**
     * 关闭连接池
     */
    public void close() {
        if (jedisPool != null && !jedisPool.isClosed()) {
            jedisPool.close();
            logger.info("Redis连接池已关闭");
        }
    }
}